/*
 * @Author: youngqj youngqj@126.com
 * @Date: 2024-10-21 18:48:37
 * @LastEditors: youngqj youngqj@126.com
 * @LastEditTime: 2024-12-03 18:47:02
 * @FilePath: /mallSystem/middleware/auth_middleware.go
 * @Description: 用户认证相关中间件
 *
 * Copyright © Zhejiang Xiaoqu Information Technology Co., Ltd, All Rights Reserved.
 */
package middleware

import (
	"context"
	"fmt"
	"strings"
	"time"
	"xiaoquio/web/core/config"
	"xiaoquio/web/core/utils"

	"github.com/gin-gonic/gin"
)

// AuthMiddleware 验证 Token 并检查 DeviceID
func AuthMiddleware() gin.HandlerFunc {

	siteConfig, _ := config.LoadConfig("../config/config.yaml")
	jwtKey := siteConfig.GetString("siteConfig.auth_jwt_key")

	return func(c *gin.Context) {
		authHeader := c.GetHeader("Authorization")
		deviceID := c.GetHeader("Device-ID")

		// 检查 Authorization 格式
		if authHeader == "" || !strings.HasPrefix(authHeader, "Bearer ") {
			utils.ResponseNilData(c, 401, "token没传")
			c.Abort()
			return
		}
		// 提取 Token
		tokenString := strings.TrimPrefix(authHeader, "Bearer ")

		// 解析并验证 Token
		claims, err := utils.ParseToken(tokenString, deviceID, []byte(jwtKey))
		if err != nil {
			// 判断错误类型，返回相应错误信息
			if err == utils.ErrDeviceIDMismatch {
				utils.ResponseNilData(c, 401, "您是不是换设备了")
			} else {
				utils.ResponseNilData(c, 401, "token已经失效了")
			}
			c.Abort()
			return
		}

		rds, err := GetRedis(c)
		if err != nil {
			utils.ResponseNilData(c, 500, "无法连接到 Redis")
			c.Abort()
			return
		}
		tokenKey := fmt.Sprintf("user:%s:access_token", claims.UserID)

		ctx := context.Background()
		existsKey, err := rds.Exists(ctx, tokenKey).Result()
		if err != nil {
			utils.ResponseNilData(c, 500, "Redis 检查操作失败")
			c.Abort()
			return
		}
		if existsKey == 0 { //Token 不存在了
			utils.ResponseNilData(c, 401, "Token 失效了请重新登录或者refresh Token")
			c.Abort()
			return
		}

		timestamp := claims.ExpiresAt.Unix() // 获取Token UNIX 时间戳
		currentTimestamp := time.Now().Unix()
		diffTimestamp := currentTimestamp - timestamp
		if diffTimestamp >= 0 {
			fmt.Println("accesstoken 过期啦！")
			utils.ResponseNilData(c, 401, "token已经失效了")
			c.Abort()
			return
		}

		//fmt.Printf("时间戳: %d\n", timestamp)
		//fmt.Printf("时间戳: %d\n", currentTimestamp)

		// Token 验证通过，将用户信息存入上下文
		c.Set("userID", claims.UserID)
		c.Next()
	}

}
